function convertMusubiAccountToXMPP4MOZAccount(aObj) {
  //TODO check connectionSecurity.
  var connectionSecurity = 0;
  switch (aObj.connectionSecurity) {
  case "None":
    connectionSecurity = 0;
    break;
  case "StartTLS":
    connectionSecurity = 1;
    break;
  };
  //TODO PASSWORD!!!
  return {
    name:               aObj.name,
    jid:                aObj.address,
    password:           aObj.name,
    connectionHost:     aObj.connectionHost,
    connectionPort:     aObj.connectionPort,
    connectionSecurity: connectionSecurity,
    channel:            null
  };
}

function DOMToE4X(aDOMNode) {
  return new XML(new XMLSerializer().serializeToString(aDOMNode));
}

function E4XToDOM(aE4XXML) {
  return window.content.document.importNode(
    new DOMParser().
          parseFromString(aE4XXML.toXMLString(), "application/xml").
		      documentElement,
    true);
}

function xmppConnect(aAccount) {
  function toYouP(stanza) {
    return stanza != undefined && XMPP.JID(stanza.@to).address == XMPP.JID(aAccount.jid).address;
  }

  XMPP.up(aAccount);
  XMPP.send(aAccount, <presence/>);
  aAccount.channel = XMPP.createChannel();
  aAccount.channel.on({
                       direction : "in",
                       event     : "message",
                       stanza    : toYouP
                      },
                      _handleMessage);
}

function _handleMessage(aMessage) {
  if (!aMessage.stanza.body.length()) return;
  // for window's browser.
	var elts = null;
  elts = window.content.document.documentElement.
           getElementsByTagName("XmppIn");
	if (elts.length) {
	  elts[0].appendChild(E4XToDOM(aMessage.stanza));
	}
  // for sidebar's top-iframe.
  elts = gMainWindow.document.getElementById("sidebar").contentDocument.
           getElementById("top-iframe").contentDocument.
           getElementsByTagName("XmppIn");
	if (elts.length) {
	  elts[0].appendChild(E4XToDOM(aMessage.stanza));
	}
}

function xmppDisconnect(aAccount) {
  aAccount.channel.release();
  XMPP.down(aAccount);
}

//jabber:x:oob is XEP-0066 Out of Band Data.
function xmppSendPage(aAddress, aSendto, aURL) {
  aURL = aURL || storeHTML();
  XMPP.send(aAddress,
    <message to={aSendto} type="chat">
	    <body>{aURL}</body>
	    <x xmlns="jabber:x:oob">
        <url>{aURL}</url>
        <desc>{window.content.document.title}</desc>
      </x>
	  </message>);
}

function handleSendRequestFromDocument(evt) {
  var xml = DOMToE4X(evt.target);
  var userBar   = gMainWindow.document.getElementById("musubi-userbar");
  var sendtoBar = gMainWindow.document.getElementById("musubi-sendtobar");
  sendtoBar.value.split(",").forEach(function(x) {
    xml.@to = x;
    XMPP.send(userBar.value, xml);
  });
}

function wwwwww(xml) {
  p(xml.toString());
  // for sidebar's top-iframe.
  var elts = gMainWindow.document.getElementById("sidebar").contentDocument.
               getElementById("top-iframe").contentDocument.
               getElementsByTagName("XmppIn");
  if (elts.length) {
	  elts[0].appendChild(E4XToDOM(xml));
	}
}

function handleCommunicationFromSidebarIframe(evt) {
  var xml = DOMToE4X(evt.target);
  var userBar   = gMainWindow.document.getElementById("musubi-userbar");
  var sendtoBar = gMainWindow.document.getElementById("musubi-sendtobar");
  switch (xml.name().localName) {
  case "message":
    sendtoBar.value.split(",").forEach(function(x) {
      xml.@to = x;
      XMPP.send(userBar.value, xml);
    });
    break;
  case "iq":
    break;
  case "presence":
    break;
  case "musubi":
    if (xml.connect.length()) {
      xmppConnect(_u(userBar.value));
    } else if (xml.disconnect.length()) {
      xmppDisconnect(_u(userBar.value));
    } else if (xml.sendpage.length()) {
      xmppSendPage(userBar.value, sendtoBar.value);
    } else if (xml.urlmsg.length()) {
      var urlmsgFrom  = xml.urlmsg.from.toString();
      var urlmsgURL   = xml.urlmsg.url.toString();
      var urlmsgDesc  = xml.urlmsg.desc.toString();
      openUILink("xmpp:" + urlmsgFrom + "?href;url=" + urlmsgURL, "Tab");
    } else if (xml.sender.length()) {
      //TODO implement.
      //var sender = xml.sender.toString();
      //openUILink("xmpp:" + sender, "Tab");
    } else if (xml.accounts.length() && xml.accounts.@type == "get") {
      var element = <musubi><accounts type="result"/></musubi>;
      if (xml.accounts.account.length()) {
        var accountXML = callWithMusubiDB(function(msbdb) {
          var id = xml.accounts.account[0].@id.toString();
          return msbdb.account.objectToE4X(msbdb.account.findById(id)[0]);
        });
        element.accounts.appendChild(accountXML);
        wwwwww(element);
      } else {
        var accountXMLs = callWithMusubiDB(function(msbdb) {
          return msbdb.account.findAll().map(msbdb.account.objectToE4X);
        });
        accountXMLs.forEach(function(x) {
          element.accounts.appendChild(x);
        });
        wwwwww(element);
      }
    } else if (xml.accounts.length() && xml.accounts.@type == "set") {
      callWithMusubiDB(function(msbdb) {
        try {
          for (var i = 0; i < xml.accounts.account.length(); i++) {
            var account = new msbdb.account(msbdb.account.E4XToObject(xml.accounts.account[i]));
            if (msbdb.account.countById(account.id)) {
              msbdb.account.update(account);
            } else {
              msbdb.account.insert(account);
            }
          }
        } catch(e) {
          p(e.name + ": " + e.message);
        }
      });
    }
    break;
  default:
    p(xml.name().localName);
    break;
  }
}

function _u(aUserAddress) {
  var a = callWithMusubiDB(function(msbdb) {
                             return msbdb.account.findByAddress(aUserAddress)[0];
                           });
  return convertMusubiAccountToXMPP4MOZAccount(a);
}

function onPageLoad(event) {
  if (event.originalTarget instanceof HTMLDocument) {
    var doc = event.originalTarget;
    if (event.originalTarget.defaultView.frameElement) {
      // Frame within a tab was loaded. doc should be the root document of
      // the frameset. If you don't want do anything when frames/iframes
      // are loaded in this web page, uncomment the following line:
      // return;
      // Find the root document:
      while (doc.defaultView.frameElement) {
        doc=doc.defaultView.frameElement.ownerDocument;
      }
    }
    doc.addEventListener("XmppEvent", handleSendRequestFromDocument, false, true);
  }
}

function onPageUnload(event) {
  if (event.originalTarget instanceof HTMLDocument) {
    var doc = event.originalTarget;
    if (event.originalTarget.defaultView.frameElement) {
      // Frame within a tab was loaded. doc should be the root document of
      // the frameset. If you don't want do anything when frames/iframes
      // are loaded in this web page, uncomment the following line:
      // return;
      // Find the root document:
      while (doc.defaultView.frameElement) {
        doc=doc.defaultView.frameElement.ownerDocument;
      }
    }
    doc.removeEventListener("XmppEvent", handleSendRequestFromDocument, false, true);
  }
}

function onPageLoadSidebarIframe(event) {
  if (event.originalTarget instanceof HTMLDocument) {
    var doc = event.originalTarget;
    if (event.originalTarget.defaultView.frameElement) {
      // Frame within a tab was loaded. doc should be the root document of
      // the frameset. If you don't want do anything when frames/iframes
      // are loaded in this web page, uncomment the following line:
      // return;
      // Find the root document:
      while (doc.defaultView.frameElement) {
        doc=doc.defaultView.frameElement.ownerDocument;
      }
    }
    doc.addEventListener("XmppEvent", handleCommunicationFromSidebarIframe, false, true);
  }
}

function onPageUnloadSidebarIframe(event) {
  if (event.originalTarget instanceof HTMLDocument) {
    var doc = event.originalTarget;
    if (event.originalTarget.defaultView.frameElement) {
      // Frame within a tab was loaded. doc should be the root document of
      // the frameset. If you don't want do anything when frames/iframes
      // are loaded in this web page, uncomment the following line:
      // return;
      // Find the root document:
      while (doc.defaultView.frameElement) {
        doc=doc.defaultView.frameElement.ownerDocument;
      }
    }
    doc.removeEventListener("XmppEvent", handleCommunicationFromSidebarIframe, false, true);
  }
}

// Add a callback to be run every time a document loads.
// note that this includes frames/iframes within the document
gMainWindow.getBrowser().addEventListener("load",   onPageLoad,   true);
gMainWindow.getBrowser().addEventListener("unload", onPageUnload, true);

window.document.addEventListener("load", function(e) {
  var topIframe = window.document.getElementById("top-iframe");
  topIframe.addEventListener("load",   onPageLoadSidebarIframe, true);
  topIframe.addEventListener("unload", onPageUnloadSidebarIframe, true);
}, true);
